home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / POV-Ray 3.0.2 / src / SOURCE / LATHE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-13  |  30.2 KB  |  1,413 lines  |  [TEXT/CWIE]

  1. /****************************************************************************
  2. *                   lathe.c
  3. *
  4. *  This module implements functions that manipulate lathes.
  5. *
  6. *  This module was written by Dieter Bayer [DB].
  7. *
  8. *  from Persistence of Vision(tm) Ray Tracer
  9. *  Copyright 1996 Persistence of Vision Team
  10. *---------------------------------------------------------------------------
  11. *  NOTICE: This source code file is provided so that users may experiment
  12. *  with enhancements to POV-Ray and to port the software to platforms other
  13. *  than those supported by the POV-Ray Team.  There are strict rules under
  14. *  which you are permitted to use this file.  The rules are in the file
  15. *  named POVLEGAL.DOC which should be distributed with this file. If
  16. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  17. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  18. *  Forum.  The latest version of POV-Ray may be found there as well.
  19. *
  20. * This program is based on the popular DKB raytracer version 2.12.
  21. * DKBTrace was originally written by David K. Buck.
  22. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  23. *
  24. *****************************************************************************/
  25.  
  26. /****************************************************************************
  27. *
  28. *  Explanation:
  29. *
  30. *    The lathe primitive is defined by a set of points in 2d space which
  31. *    are interpolated by linear, quadratic, or cubic splines. The resulting
  32. *    2d curve is rotated about an axis to form the final lathe object.
  33. *
  34. *    All calculations are done in the object's (u,v,w)-coordinate system
  35. *    with the (w)-axis being the rotation axis.
  36. *
  37. *    One spline segment in the (r,w)-plane is given by the equations
  38. *
  39. *      fw(t) = Aw * t^3 + Bw * t^2 + Cw * t + Dw  and
  40. *      fr(t) = Ar * t^3 + Br * t^2 + Cr * t + Dr,
  41. *
  42. *    with the parameter t ranging from 0 to 1 and r = sqrt(u*u+v*v).
  43. *
  44. *    To intersect a ray R = P + k * D transformed into the object's
  45. *    coordinate system with the lathe object, the equations
  46. *
  47. *      (Pu + k * Du)^2 + (Pv + k * Dv)^2 = (fr(t))^2
  48. *                          (Pw + k * Dw) = fw(t)
  49. *
  50. *    have to be solved for t. For valid intersections (0 <= t <= 1)
  51. *    the corresponding k can be calculated from one of the above equations.
  52. *
  53. *    Note that the degree of the polynomal to solve is two times the
  54. *    degree of the spline segments used.
  55. *
  56. *    Note that Pu, Pv, Pw and Du, Dv, Dw denote the coordinates
  57. *    of the vectors P and D.
  58. *
  59. *  Syntax:
  60. *
  61. *    lathe
  62. *    {
  63. *      [ linear_spline | quadratic_spline | cubic_spline ]
  64. *
  65. *      number_of_points,
  66. *
  67. *      <P[0]>, <P[1], ..., <P[n-1]>
  68. *
  69. *      [ sturm ]
  70. *    }
  71. *
  72. *    Note that the P[i] are 2d vectors.
  73. *
  74. *    Linear interpolation is used by default. In this case all n Points
  75. *    are used. In the quadratic case the first point is used to determine
  76. *    the derivates at the starting point P[1]. In the cubic case
  77. *    the first and last points are used to determine the derivatives at
  78. *    the starting point P[1] and ending point P[n-2].
  79. *
  80. *    To get a closed (and smooth) curve you have make sure that
  81. *
  82. *      P[0] = P[n-1] in the linear case,
  83. *
  84. *      P[0] = P[n-2] and P[1] = P[n-1] in the quadratic case, and
  85. *
  86. *      P[0] = P[n-3] and P[1] = P[n-2] and P[2] = P[n-1] in the cubic case.
  87. *
  88. *    Note that the x coordinate of a point corresponds to the r coordinate
  89. *    and the y coordinate to the w coordinate;
  90. *
  91. *  ---
  92. *
  93. *  Ideas for the lathe were taken from:
  94. *
  95. *    P. Burger and D. Gillies, "Rapid Ray Tracing of General Surfaces
  96. *    of Revolution", New Advances in Computer Graphics, Proceedings
  97. *    of CG International '89, R. A. Earnshaw, B. Wyvill (Eds.),
  98. *    Springer, ..., pp. 523-531
  99. *
  100. *    P. Burger and D. Gillies, "Swept Surfaces", Interactive Computer
  101. *    Graphics, Addison-Wesley, 1989, pp. 376-380
  102. *
  103. *  ---
  104. *
  105. *  Jun 1994 : Creation. [DB]
  106. *
  107. *****************************************************************************/
  108.  
  109. #include "frame.h"
  110. #include "povray.h"
  111. #include "vector.h"
  112. #include "povproto.h"
  113. #include "bbox.h"
  114. #include "lathe.h"
  115. #include "polysolv.h"
  116. #include "matrices.h"
  117. #include "objects.h"
  118. #include "torus.h"
  119.  
  120.  
  121.  
  122. /*****************************************************************************
  123. * Local preprocessor defines
  124. ******************************************************************************/
  125.  
  126. /* Minimal intersection depth for a valid intersection. */
  127.  
  128. #define DEPTH_TOLERANCE 1.0e-4
  129.  
  130. /* Max. number of intersecions per spline segment. */
  131.  
  132. #define MAX_INTERSECTIONS_PER_SEGMENT 4
  133.  
  134.  
  135.  
  136. /*****************************************************************************
  137. * Local typedefs
  138. ******************************************************************************/
  139.  
  140.  
  141.  
  142. /*****************************************************************************
  143. * Static functions
  144. ******************************************************************************/
  145.  
  146. static int  intersect_lathe PARAMS((RAY *Ray, LATHE *Lathe, ISTACK *Depth_Stack));
  147. static int  All_Lathe_Intersections PARAMS((OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack));
  148. static int  Inside_Lathe PARAMS((VECTOR point, OBJECT *Object));
  149. static void Lathe_Normal PARAMS((VECTOR Result, OBJECT *Object, INTERSECTION *Inter));
  150. static void *Copy_Lathe PARAMS((OBJECT *Object));
  151. static void Translate_Lathe PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
  152. static void Rotate_Lathe PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
  153. static void Scale_Lathe PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
  154. static void Transform_Lathe PARAMS((OBJECT *Object, TRANSFORM *Trans));
  155. static void Invert_Lathe PARAMS((OBJECT *Object));
  156. static void Destroy_Lathe PARAMS((OBJECT *Object));
  157.  
  158. static int  test_hit PARAMS((LATHE *, RAY *, ISTACK *, DBL, DBL, int));
  159.  
  160.  
  161. /*****************************************************************************
  162. * Local variables
  163. ******************************************************************************/
  164.  
  165. static METHODS Lathe_Methods =
  166. {
  167.   All_Lathe_Intersections,
  168.   Inside_Lathe, Lathe_Normal,
  169.   Copy_Lathe,
  170.   Translate_Lathe, Rotate_Lathe,
  171.   Scale_Lathe, Transform_Lathe, Invert_Lathe, Destroy_Lathe
  172. };
  173.  
  174.  
  175.  
  176. /*****************************************************************************
  177. *
  178. * FUNCTION
  179. *
  180. *   All_Lathe_Intersections
  181. *
  182. * INPUT
  183. *
  184. *   Object      - Object
  185. *   Ray         - Ray
  186. *   Depth_Stack - Intersection stack
  187. *
  188. * OUTPUT
  189. *
  190. *   Depth_Stack
  191. *
  192. * RETURNS
  193. *
  194. *   int - TRUE, if a intersection was found
  195. *   
  196. * AUTHOR
  197. *
  198. *   Dieter Bayer
  199. *   
  200. * DESCRIPTION
  201. *
  202. *   Determine ray/lathe intersection and clip intersection found.
  203. *
  204. * CHANGES
  205. *
  206. *   Jun 1994 : Creation.
  207. *   Oct 1996 : Changed code to include faster version. [DB]
  208. *
  209. ******************************************************************************/
  210.  
  211. static int All_Lathe_Intersections(Object, Ray, Depth_Stack)
  212. OBJECT *Object;
  213. RAY *Ray;
  214. ISTACK *Depth_Stack;
  215. {
  216.   Increase_Counter(stats[Ray_Lathe_Tests]);
  217.  
  218.   if (intersect_lathe(Ray, (LATHE *)Object, Depth_Stack))
  219.   {
  220.     Increase_Counter(stats[Ray_Lathe_Tests_Succeeded]);
  221.  
  222.     return(TRUE);
  223.   }
  224.  
  225.   return(FALSE);
  226. }
  227.  
  228.  
  229.  
  230. /*****************************************************************************
  231. *
  232. * FUNCTION
  233. *
  234. *   intersect_lathe
  235. *
  236. * INPUT
  237. *
  238. *   Ray          - Ray
  239. *   Lathe        - Lathe
  240. *   Intersection - Lathe intersection structure
  241. *
  242. * OUTPUT
  243. *
  244. *   Intersection
  245. *
  246. * RETURNS
  247. *
  248. *   int - Number of intersections found
  249. *
  250. * AUTHOR
  251. *
  252. *   Dieter Bayer
  253. *
  254. * DESCRIPTION
  255. *
  256. *   Determine ray/lathe intersection.
  257. *
  258. *   NOTE: The curve is rotated about the y-axis!
  259. *         Order of the polynomial must not be used!
  260. *
  261. * CHANGES
  262. *
  263. *   Jun 1994 : Creation.
  264. *   Oct 1996 : Changed code to include faster version. [DB]
  265. *
  266. ******************************************************************************/
  267.  
  268. static int intersect_lathe(Ray, Lathe, Depth_Stack)
  269. RAY *Ray;
  270. LATHE *Lathe;
  271. ISTACK *Depth_Stack;
  272. {
  273.   int cnt;
  274.   int found, j, n1, n2;
  275.   DBL k, len, r, m, w, Dy2, r0;
  276.   DBL x1[7], x2[3], y1[6], y2[2];
  277.   DBL best;
  278.   VECTOR P, D;
  279.   BCYL_INT *intervals;
  280.   LATHE_SPLINE_ENTRY *Entry;
  281.  
  282.   /* Transform the ray into the lathe space. */
  283.  
  284.   MInvTransPoint(P, Ray->Initial, Lathe->Trans);
  285.  
  286.   MInvTransDirection(D, Ray->Direction, Lathe->Trans);
  287.  
  288.   VLength(len, D);
  289.  
  290.   VInverseScaleEq(D, len);
  291.  
  292.   /* Test if ray misses lathe's cylindrical bound. */
  293.  
  294. #ifdef LATHE_EXTRA_STATS
  295.   Increase_Counter(stats[Lathe_Bound_Tests]);
  296. #endif
  297.  
  298.   if (((D[Y] >= 0.0) && (P[Y] >  Lathe->Height2)) ||
  299.       ((D[Y] <= 0.0) && (P[Y] <  Lathe->Height1)) ||
  300.       ((D[X] >= 0.0) && (P[X] >  Lathe->Radius2)) ||
  301.       ((D[X] <= 0.0) && (P[X] < -Lathe->Radius2)))
  302.   {
  303.     return(FALSE);
  304.   }
  305.  
  306.   /* Get distance r0 of the ray from rotation axis (i.e. y axis). */
  307.  
  308.   r0 = fabs(P[X] * D[Z] - P[Z] * D[X]);
  309.  
  310.   r = D[X] * D[X] + D[Z] * D[Z];
  311.  
  312.   if (r > 0.0)
  313.   {
  314.     r0 /= sqrt(r);
  315.   }
  316.  
  317.   /* Test if ray misses lathe's cylindrical bound. */
  318.  
  319.   if (r0 > Lathe->Radius2)
  320.   {
  321.     return(FALSE);
  322.   }
  323.  
  324.   /* Intersect all cylindrical bounds. */
  325.  
  326.   if ((cnt = Intersect_BCyl(Lathe->Spline->BCyl, P, D)) == 0)
  327.   {
  328.     return(FALSE);
  329.   }
  330.  
  331. #ifdef LATHE_EXTRA_STATS
  332.   Increase_Counter(stats[Lathe_Bound_Tests_Succeeded]);
  333. #endif
  334.  
  335.   /* Precalculate some constants that are ray-dependant only. */
  336.  
  337.   m = D[X] * P[X] + D[Z] * P[Z];
  338.  
  339.   Dy2 = D[Y] * D[Y];
  340.  
  341.   /* Step through the list of intersections. */
  342.  
  343.   found = FALSE;
  344.  
  345.   best = BOUND_HUGE;
  346.  
  347.   intervals = Lathe->Spline->BCyl->intervals;
  348.  
  349.   for (j = 0; j < cnt; j++)
  350.   {
  351.     /* Get current segment. */
  352.  
  353.     Entry = &Lathe->Spline->Entry[intervals[j].n];
  354.  
  355.     /* If we already have the best intersection we may exit. */
  356.  
  357.     if (!(Lathe->Type & IS_CHILD_OBJECT) && (intervals[j].d[0] > best))
  358.     {
  359.       break;
  360.     }
  361.  
  362.     /* Init number of roots found. */
  363.  
  364.     n1 = 0;
  365.  
  366.     /* Intersect segment. */
  367.  
  368.     switch (Lathe->Spline_Type)
  369.     {
  370.       /***********************************************************************
  371.       * Linear spline.
  372.       ************************************************************************/
  373.  
  374.       case LINEAR_SPLINE:
  375.  
  376.         /* Solve 2th order polynomial. */
  377.  
  378.         x1[0] = Entry->C[Y] * Entry->C[Y] * r - Entry->C[X] * Entry->C[X] * Dy2;
  379.  
  380.         x1[1] = 2.0 * (Entry->C[Y] * ((Entry->D[Y] - P[Y]) * r + D[Y] * m) - Entry->C[X] * Entry->D[X] * Dy2);
  381.  
  382.         x1[2] = (Entry->D[Y] - P[Y]) * ((Entry->D[Y] - P[Y]) * r + 2.0 * D[Y] * m) + Dy2 * (P[X] * P[X] + P[Z] * P[Z] - Entry->D[X] * Entry->D[X]);
  383.  
  384.         n1 = Solve_Polynomial(2, x1, y1, FALSE, 0.0);
  385.  
  386.         break;
  387.  
  388.       /***********************************************************************
  389.       * Quadratic spline.
  390.       ************************************************************************/
  391.  
  392.       case QUADRATIC_SPLINE:
  393.  
  394.         /* Solve 4th order polynomial. */
  395.  
  396.         x1[0] = Entry->B[Y] * Entry->B[Y] * r - Entry->B[X] * Entry->B[X] * Dy2;
  397.  
  398.         x1[1] = 2.0 * (Entry->B[Y] * Entry->C[Y] * r - Entry->B[X] * Entry->C[X] * Dy2);
  399.  
  400.         x1[2] = r * (2.0 * Entry->B[Y] * (Entry->D[Y] - P[Y]) + Entry->C[Y] * Entry->C[Y]) + 2.0 * Entry->B[Y] * D[Y] * m - (2.0 * Entry->B[X] * Entry->D[X] + Entry->C[X] * Entry->C[X]) * Dy2;
  401.  
  402.         x1[3] = 2.0 * (Entry->C[Y] * ((Entry->D[Y] - P[Y]) * r + D[Y] * m) - Entry->C[X] * Entry->D[X] * Dy2);
  403.  
  404.         x1[4] = (Entry->D[Y] - P[Y]) * ((Entry->D[Y] - P[Y]) * r + 2.0 * D[Y] * m) + Dy2 * (P[X] * P[X] + P[Z] * P[Z] - Entry->D[X] * Entry->D[X]);
  405.  
  406.         n1 = Solve_Polynomial(4, x1, y1, Test_Flag(Lathe, STURM_FLAG), 0.0);
  407.  
  408.         break;
  409.  
  410.       /***********************************************************************
  411.       * Cubic spline.
  412.       ************************************************************************/
  413.  
  414.       case CUBIC_SPLINE:
  415.  
  416.         /* Solve 6th order polynomial. */
  417.  
  418.         x1[0] = Entry->A[Y] * Entry->A[Y] * r - Entry->A[X] * Entry->A[X] * Dy2;
  419.  
  420.         x1[1] = 2.0 * (Entry->A[Y] * Entry->B[Y] * r - Entry->A[X] * Entry->B[X] * Dy2);
  421.  
  422.         x1[2] = (2.0 * Entry->A[Y] * Entry->C[Y] + Entry->B[Y] * Entry->B[Y]) * r - (2.0 * Entry->A[X] * Entry->C[X] + Entry->B[X] * Entry->B[X]) * Dy2;
  423.  
  424.         x1[3] = 2.0 * ((Entry->A[Y] * Entry->D[Y] + Entry->B[Y] * Entry->C[Y] - Entry->A[Y] * P[Y]) * r + Entry->A[Y] * D[Y] * m - (Entry->A[X] * Entry->D[X] + Entry->B[X] * Entry->C[X]) * Dy2);
  425.  
  426.         x1[4] = (2.0 * Entry->B[Y] * (Entry->D[Y] - P[Y]) + Entry->C[Y] * Entry->C[Y]) * r + 2.0 * Entry->B[Y] * D[Y] * m - (2.0 * Entry->B[X] * Entry->D[X] + Entry->C[X] * Entry->C[X]) * Dy2;
  427.  
  428.         x1[5] = 2.0 * (Entry->C[Y] * ((Entry->D[Y] - P[Y]) * r + D[Y] * m) - Entry->C[X] * Entry->D[X] * Dy2);
  429.  
  430.         x1[6] = (Entry->D[Y] - P[Y]) * ((Entry->D[Y] - P[Y]) * r + 2.0 * D[Y] * m) + Dy2 * (P[X] * P[X] + P[Z] * P[Z] - Entry->D[X] * Entry->D[X]);
  431.  
  432.         n1 = Solve_Polynomial(6, x1, y1, Test_Flag(Lathe, STURM_FLAG), 0.0);
  433.  
  434.         break;
  435.     }
  436.  
  437.     /* Test roots for valid intersections. */
  438.  
  439.     while (n1--)
  440.     {
  441.       w = y1[n1];
  442.  
  443.       if ((w >= 0.0) && (w <= 1.0))
  444.       {
  445.         if (fabs(D[Y]) > EPSILON)
  446.         {
  447.           k = (w * (w * (w * Entry->A[Y] + Entry->B[Y]) + Entry->C[Y]) + Entry->D[Y] - P[Y]) / D[Y];
  448.  
  449.           if (test_hit(Lathe, Ray, Depth_Stack, k / len, w, intervals[j].n))
  450.           {
  451.             found = TRUE;
  452.  
  453.             if (k < best)
  454.             {
  455.               best = k;
  456.             }
  457.           }
  458.         }
  459.         else
  460.         {
  461.           k = w * (w * (w * Entry->A[X] + Entry->B[X]) + Entry->C[X]) + Entry->D[X];
  462.  
  463.           x2[0] = r;
  464.           x2[1] = 2.0 * m;
  465.  
  466.           x2[2] = P[X] * P[X] + P[Z] * P[Z] - k * k;
  467.  
  468.           n2 = Solve_Polynomial(2, x2, y2, FALSE, 0.0);
  469.  
  470.           while (n2--)
  471.           {
  472.             k = y2[n2];
  473.  
  474.             if (test_hit(Lathe, Ray, Depth_Stack, k / len, w, intervals[j].n))
  475.             {
  476.               found = TRUE;
  477.  
  478.               if (k < best)
  479.               {
  480.                 best = k;
  481.               }
  482.             }
  483.           }
  484.         }
  485.       }
  486.     }
  487.   }
  488.  
  489.   return(found);
  490. }
  491.  
  492.  
  493.  
  494. /*****************************************************************************
  495. *
  496. * FUNCTION
  497. *
  498. *   Inside_Lathe
  499. *
  500. * INPUT
  501. *
  502. *   IPoint - Intersection point
  503. *   Object - Object
  504. *   
  505. * OUTPUT
  506. *   
  507. * RETURNS
  508. *
  509. *   int - TRUE if inside
  510. *   
  511. * AUTHOR
  512. *
  513. *   Dieter Bayer
  514. *   
  515. * DESCRIPTION
  516. *
  517. *   Test if a point lies inside the lathe.
  518. *
  519. * CHANGES
  520. *
  521. *   Jun 1994 : Creation.
  522. *
  523. ******************************************************************************/
  524.  
  525. static int Inside_Lathe(IPoint, Object)
  526. VECTOR IPoint;
  527. OBJECT *Object;
  528. {
  529.   int i, n, NC;
  530.   DBL r, k, w;
  531.   DBL x[4], y[3];
  532.   DBL *height, *radius;
  533.   VECTOR P;
  534.   BCYL_ENTRY *entry;
  535.   LATHE_SPLINE_ENTRY *Entry;
  536.   LATHE *Lathe = (LATHE *)Object;
  537.  
  538.   height = Lathe->Spline->BCyl->height;
  539.  
  540.   radius = Lathe->Spline->BCyl->radius;
  541.  
  542.   entry = Lathe->Spline->BCyl->entry;
  543.  
  544.   /* Transform the point into the lathe space. */
  545.  
  546.   MInvTransPoint(P, IPoint, Lathe->Trans);
  547.  
  548.   /* Number of crossings. */
  549.  
  550.   NC = 0;
  551.  
  552.   if ((P[Y] >= Lathe->Height1) && (P[Y] <= Lathe->Height2))
  553.   {
  554.     r = sqrt(P[X] * P[X] + P[Z] * P[Z]);
  555.  
  556.     if ((r >= Lathe->Radius1) && (r <= Lathe->Radius2))
  557.     {
  558.       for (i = 0; i < Lathe->Number; i++)
  559.       {
  560.         Entry = &Lathe->Spline->Entry[i];
  561.  
  562.         /* Test if we are inside the segments cylindrical bound. */
  563.  
  564.         if ((P[Y] >= height[entry[i].h1] - EPSILON) &&
  565.             (P[Y] <= height[entry[i].h2] + EPSILON))
  566.         {
  567.           x[0] = Entry->A[Y];
  568.           x[1] = Entry->B[Y];
  569.           x[2] = Entry->C[Y];
  570.           x[3] = Entry->D[Y] - P[Y];
  571.  
  572.           n = Solve_Polynomial(3, x, y, Test_Flag(Lathe, STURM_FLAG), 0.0);
  573.  
  574.           while (n--)
  575.           {
  576.             w = y[n];
  577.  
  578.             if ((w >= 0.0) && (w <= 1.0))
  579.             {
  580.               k  = w * (w * (w * Entry->A[X] + Entry->B[X]) + Entry->C[X]) + Entry->D[X] - r;
  581.  
  582.               if (k >= 0.0)
  583.               {
  584.                 NC++;
  585.               }
  586.             }
  587.           }
  588.         }
  589.       }
  590.     }
  591.   }
  592.  
  593.   if (NC & 1)
  594.   {
  595.     return(!Test_Flag(Lathe, INVERTED_FLAG));
  596.   }
  597.   else
  598.   {
  599.     return(Test_Flag(Lathe, INVERTED_FLAG));
  600.   }
  601. }
  602.  
  603.  
  604.  
  605. /*****************************************************************************
  606. *
  607. * FUNCTION
  608. *
  609. *   Lathe_Normal
  610. *
  611. * INPUT
  612. *
  613. *   Result - Normal vector
  614. *   Object - Object
  615. *   Inter  - Intersection found
  616. *   
  617. * OUTPUT
  618. *
  619. *   Result
  620. *   
  621. * RETURNS
  622. *   
  623. * AUTHOR
  624. *
  625. *   Dieter Bayer
  626. *   
  627. * DESCRIPTION
  628. *
  629. *   Calculate the normal of the lathe in a given point.
  630. *
  631. * CHANGES
  632. *
  633. *   Jun 1994 : Creation.
  634. *
  635. ******************************************************************************/
  636.  
  637. static void Lathe_Normal(Result, Object, Inter)
  638. OBJECT *Object;
  639. VECTOR Result;
  640. INTERSECTION *Inter;
  641. {
  642.   DBL r, dx, dy;
  643.   VECTOR P, N;
  644.   LATHE *Lathe = (LATHE *)Object;
  645.   LATHE_SPLINE_ENTRY *Entry;
  646.  
  647.   Entry = &Lathe->Spline->Entry[Inter->i1];
  648.  
  649.   /* Transform the point into the lathe space. */
  650.  
  651.   MInvTransPoint(P, Inter->IPoint, Lathe->Trans);
  652.  
  653.   /* Get distance from rotation axis. */
  654.  
  655.   r = P[X] * P[X] + P[Z] * P[Z];
  656.  
  657.   if (r > EPSILON)
  658.   {
  659.     r = sqrt(r);
  660.  
  661.     /* Get derivatives. */
  662.  
  663.     dx = Inter->d1 * (3.0 * Entry->A[X] * Inter->d1 + 2.0 * Entry->B[X]) + Entry->C[X];
  664.     dy = Inter->d1 * (3.0 * Entry->A[Y] * Inter->d1 + 2.0 * Entry->B[Y]) + Entry->C[Y];
  665.  
  666.     /* Get normal by rotation. */
  667.  
  668.     N[X] =  dy * P[X];
  669.     N[Y] = -dx * r;
  670.     N[Z] =  dy * P[Z];
  671.   }
  672.   else
  673.   {
  674.     N[X] = N[Z] = 0.0; N[Y] = 1.0;
  675.   }
  676.  
  677.   /* Transform the normalt out of the lathe space. */
  678.  
  679.   MTransNormal(Result, N, Lathe->Trans);
  680.  
  681.   VNormalize(Result, Result);
  682. }
  683.  
  684.  
  685.  
  686. /*****************************************************************************
  687. *
  688. * FUNCTION
  689. *
  690. *   Translate_Lathe
  691. *
  692. * INPUT
  693. *
  694. *   Object - Object
  695. *   Vector - Translation vector
  696. *   
  697. * OUTPUT
  698. *
  699. *   Object
  700. *   
  701. * RETURNS
  702. *   
  703. * AUTHOR
  704. *
  705. *   Dieter Bayer
  706. *   
  707. * DESCRIPTION
  708. *
  709. *   Translate a lathe.
  710. *
  711. * CHANGES
  712. *
  713. *   Jun 1994 : Creation.
  714. *
  715. ******************************************************************************/
  716.  
  717. static void Translate_Lathe(Object, Vector, Trans)
  718. OBJECT *Object;
  719. VECTOR Vector;
  720. TRANSFORM *Trans;
  721. {
  722.   Transform_Lathe(Object, Trans);
  723. }
  724.  
  725.  
  726.  
  727. /*****************************************************************************
  728. *
  729. * FUNCTION
  730. *
  731. *   Rotate_Lathe
  732. *
  733. * INPUT
  734. *
  735. *   Object - Object
  736. *   Vector - Rotation vector
  737. *   
  738. * OUTPUT
  739. *
  740. *   Object
  741. *   
  742. * RETURNS
  743. *   
  744. * AUTHOR
  745. *
  746. *   Dieter Bayer
  747. *   
  748. * DESCRIPTION
  749. *
  750. *   Rotate a lathe.
  751. *
  752. * CHANGES
  753. *
  754. *   Jun 1994 : Creation.
  755. *
  756. ******************************************************************************/
  757.  
  758. static void Rotate_Lathe(Object, Vector, Trans)
  759. OBJECT *Object;
  760. VECTOR Vector;
  761. TRANSFORM *Trans;
  762. {
  763.   Transform_Lathe(Object, Trans);
  764. }
  765.  
  766.  
  767.  
  768. /*****************************************************************************
  769. *
  770. * FUNCTION
  771. *
  772. *   Scale_Lathe
  773. *
  774. * INPUT
  775. *
  776. *   Object - Object
  777. *   Vector - Scaling vector
  778. *   
  779. * OUTPUT
  780. *
  781. *   Object
  782. *   
  783. * RETURNS
  784. *   
  785. * AUTHOR
  786. *
  787. *   Dieter Bayer
  788. *   
  789. * DESCRIPTION
  790. *
  791. *   Scale a lathe.
  792. *
  793. * CHANGES
  794. *
  795. *   Jun 1994 : Creation.
  796. *
  797. ******************************************************************************/
  798.  
  799. static void Scale_Lathe(Object, Vector, Trans)
  800. OBJECT *Object;
  801. VECTOR Vector;
  802. TRANSFORM *Trans;
  803. {
  804.   Transform_Lathe(Object, Trans);
  805. }
  806.  
  807.  
  808.  
  809. /*****************************************************************************
  810. *
  811. * FUNCTION
  812. *
  813. *   Transform_Lathe
  814. *
  815. * INPUT
  816. *
  817. *   Object - Object
  818. *   Trans  - Transformation to apply
  819. *   
  820. * OUTPUT
  821. *
  822. *   Object
  823. *   
  824. * RETURNS
  825. *   
  826. * AUTHOR
  827. *
  828. *   Dieter Bayer
  829. *   
  830. * DESCRIPTION
  831. *
  832. *   Transform a lathe and recalculate its bounding box.
  833. *
  834. * CHANGES
  835. *
  836. *   Jun 1994 : Creation.
  837. *
  838. ******************************************************************************/
  839.  
  840. static void Transform_Lathe(Object, Trans)
  841. OBJECT *Object;
  842. TRANSFORM *Trans;
  843. {
  844.   Compose_Transforms(((LATHE *)Object)->Trans, Trans);
  845.  
  846.   Compute_Lathe_BBox((LATHE *)Object);
  847. }
  848.  
  849.  
  850.  
  851. /*****************************************************************************
  852. *
  853. * FUNCTION
  854. *
  855. *   Invert_Lathe
  856. *
  857. * INPUT
  858. *
  859. *   Object - Object
  860. *   
  861. * OUTPUT
  862. *
  863. *   Object
  864. *   
  865. * RETURNS
  866. *   
  867. * AUTHOR
  868. *
  869. *   Dieter Bayer
  870. *   
  871. * DESCRIPTION
  872. *
  873. *   Invert a lathe.
  874. *
  875. * CHANGES
  876. *
  877. *   Jun 1994 : Creation.
  878. *
  879. ******************************************************************************/
  880.  
  881. static void Invert_Lathe(Object)
  882. OBJECT *Object;
  883. {
  884.   Invert_Flag(Object, INVERTED_FLAG);
  885. }
  886.  
  887.  
  888.  
  889. /*****************************************************************************
  890. *
  891. * FUNCTION
  892. *
  893. *   Create_Lathe
  894. *
  895. * INPUT
  896. *   
  897. * OUTPUT
  898. *   
  899. * RETURNS
  900. *
  901. *   LATHE * - new lathe
  902. *   
  903. * AUTHOR
  904. *
  905. *   Dieter Bayer
  906. *   
  907. * DESCRIPTION
  908. *
  909. *   Create a new lathe.
  910. *
  911. * CHANGES
  912. *
  913. *   Jun 1994 : Creation.
  914. *
  915. ******************************************************************************/
  916.  
  917. LATHE *Create_Lathe()
  918. {
  919.   LATHE *New;
  920.  
  921.   New = (LATHE *)POV_MALLOC(sizeof(LATHE), "lathe");
  922.  
  923.   INIT_OBJECT_FIELDS(New,LATHE_OBJECT,&Lathe_Methods)
  924.  
  925.   New->Trans = Create_Transform();
  926.  
  927.   New->Spline_Type = LINEAR_SPLINE;
  928.  
  929.   New->Number = 0;
  930.  
  931.   New->Spline = NULL;
  932.  
  933.   New->Radius1 =
  934.   New->Radius2 =
  935.   New->Height1 =
  936.   New->Height2 = 0.0;
  937.  
  938.   return(New);
  939. }
  940.  
  941.  
  942.  
  943. /*****************************************************************************
  944. *
  945. * FUNCTION
  946. *
  947. *   Copy_Lathe
  948. *
  949. * INPUT
  950. *
  951. *   Object - Object
  952. *   
  953. * OUTPUT
  954. *   
  955. * RETURNS
  956. *
  957. *   void * - New lathe
  958. *   
  959. * AUTHOR
  960. *
  961. *   Dieter Bayer
  962. *   
  963. * DESCRIPTION
  964. *
  965. *   Copy a lathe structure.
  966. *
  967. *   NOTE: The splines are not copied, only the number of references is
  968. *         counted, so that Destray_Lathe() knows if they can be destroyed.
  969. *
  970. * CHANGES
  971. *
  972. *   Jun 1994 : Creation.
  973. *
  974. *   Sep 1994 : Fixed memory leakage bug. [DB]
  975. *
  976. ******************************************************************************/
  977.  
  978. static void *Copy_Lathe(Object)
  979. OBJECT *Object;
  980. {
  981.   LATHE *New, *Lathe = (LATHE *)Object;
  982.  
  983.   New = Create_Lathe();
  984.  
  985.   /* Get rid of the transformation created in Create_Lathe(). */
  986.  
  987.   Destroy_Transform(New->Trans);
  988.  
  989.   /* Copy lathe. */
  990.  
  991.   *New = *Lathe;
  992.  
  993.   New->Trans = Copy_Transform(Lathe->Trans);
  994.  
  995.   New->Spline->References++;
  996.  
  997.   return(New);
  998. }
  999.  
  1000.  
  1001.  
  1002. /*****************************************************************************
  1003. *
  1004. * FUNCTION
  1005. *
  1006. *   Destroy_Lathe
  1007. *
  1008. * INPUT
  1009. *
  1010. *   Object - Object
  1011. *   
  1012. * OUTPUT
  1013. *
  1014. *   Object
  1015. *   
  1016. * RETURNS
  1017. *
  1018. * AUTHOR
  1019. *
  1020. *   Dieter Bayer
  1021. *
  1022. * DESCRIPTION
  1023. *
  1024. *   Destroy a lathe.
  1025. *
  1026. *   NOTE: The splines are destroyed if they are no longer used by any copy.
  1027. *
  1028. * CHANGES
  1029. *
  1030. *   Jun 1994 : Creation.
  1031. *   Oct 1996 : Changed code to include faster version. [DB]
  1032. *
  1033. ******************************************************************************/
  1034.  
  1035. static void Destroy_Lathe(Object)
  1036. OBJECT *Object;
  1037. {
  1038.   LATHE *Lathe = (LATHE *)Object;
  1039.  
  1040.   Destroy_Transform(Lathe->Trans);
  1041.  
  1042.   if (--(Lathe->Spline->References) == 0)
  1043.   {
  1044.     Destroy_BCyl(Lathe->Spline->BCyl);
  1045.  
  1046.     POV_FREE(Lathe->Spline->Entry);
  1047.  
  1048.     POV_FREE(Lathe->Spline);
  1049.   }
  1050.  
  1051.   POV_FREE (Object);
  1052. }
  1053.  
  1054.  
  1055.  
  1056. /*****************************************************************************
  1057. *
  1058. * FUNCTION
  1059. *
  1060. *   Compute_Lathe_BBox
  1061. *
  1062. * INPUT
  1063. *
  1064. *   Lathe - Lathe
  1065. *   
  1066. * OUTPUT
  1067. *
  1068. *   Lathe
  1069. *   
  1070. * RETURNS
  1071. *   
  1072. * AUTHOR
  1073. *
  1074. *   Dieter Bayer
  1075. *   
  1076. * DESCRIPTION
  1077. *
  1078. *   Calculate the bounding box of a lathe.
  1079. *
  1080. * CHANGES
  1081. *
  1082. *   Jun 1994 : Creation.
  1083. *
  1084. ******************************************************************************/
  1085.  
  1086. void Compute_Lathe_BBox(Lathe)
  1087. LATHE *Lathe;
  1088. {
  1089.   Make_BBox(Lathe->BBox, -Lathe->Radius2, Lathe->Height1, -Lathe->Radius2,
  1090.     2.0 * Lathe->Radius2, Lathe->Height2 - Lathe->Height1, 2.0 * Lathe->Radius2);
  1091.  
  1092.   Recompute_BBox(&Lathe->BBox, Lathe->Trans);
  1093. }
  1094.  
  1095.  
  1096.  
  1097. /*****************************************************************************
  1098. *
  1099. * FUNCTION
  1100. *
  1101. *   Compute_Lathe
  1102. *
  1103. * INPUT
  1104. *
  1105. *   Lathe - Lathe
  1106. *   P     - Points defining lathe
  1107. *   
  1108. * OUTPUT
  1109. *
  1110. *   Lathe
  1111. *   
  1112. * RETURNS
  1113. *
  1114. * AUTHOR
  1115. *
  1116. *   Dieter Bayer
  1117. *
  1118. * DESCRIPTION
  1119. *
  1120. *   Calculate the spline segments of a lathe from a set of points.
  1121. *
  1122. *   Note that the number of points in the lathe has to be set.
  1123. *
  1124. * CHANGES
  1125. *
  1126. *   Jun 1994 : Creation.
  1127. *   Oct 1996 : Changed code to include faster version. [DB]
  1128. *
  1129. ******************************************************************************/
  1130.  
  1131. void Compute_Lathe(Lathe, P)
  1132. LATHE *Lathe;
  1133. UV_VECT *P;
  1134. {
  1135.   int i, n;
  1136.   DBL x[4], xmin, xmax;
  1137.   DBL y[4], ymin, ymax;
  1138.   DBL c[3], r[2];
  1139.   DBL *tmp_r1;
  1140.   DBL *tmp_r2;
  1141.   DBL *tmp_h1;
  1142.   DBL *tmp_h2;
  1143.   UV_VECT A, B, C, D;
  1144.  
  1145.   /* Allocate Lathe->Number segments. */
  1146.  
  1147.   if (Lathe->Spline == NULL)
  1148.   {
  1149.     Lathe->Spline = (LATHE_SPLINE *)POV_MALLOC(sizeof(LATHE_SPLINE), "spline segments of lathe");
  1150.  
  1151.     /* Init spline. */
  1152.  
  1153.     Lathe->Spline->References = 1;
  1154.  
  1155.     Lathe->Spline->Entry = (LATHE_SPLINE_ENTRY *)POV_MALLOC(Lathe->Number*sizeof(LATHE_SPLINE_ENTRY), "spline segments of lathe");
  1156.   }
  1157.   else
  1158.   {
  1159.     /* This should never happen! */
  1160.  
  1161.     Error("Lathe segments are already defined.\n");
  1162.   }
  1163.  
  1164.   /* Allocate temporary lists. */
  1165.  
  1166.   tmp_r1 = (DBL *)POV_MALLOC(Lathe->Number * sizeof(DBL), "temp lathe data");
  1167.   tmp_r2 = (DBL *)POV_MALLOC(Lathe->Number * sizeof(DBL), "temp lathe data");
  1168.   tmp_h1 = (DBL *)POV_MALLOC(Lathe->Number * sizeof(DBL), "temp lathe data");
  1169.   tmp_h2 = (DBL *)POV_MALLOC(Lathe->Number * sizeof(DBL), "temp lathe data");
  1170.  
  1171.   /***************************************************************************
  1172.   * Calculate segments.
  1173.   ****************************************************************************/
  1174.  
  1175.   /* We want to know the size of the overall bounding cylinder. */
  1176.  
  1177.   xmax = ymax = -BOUND_HUGE;
  1178.   xmin = ymin = BOUND_HUGE;
  1179.  
  1180.   for (i = 0; i < Lathe->Number; i++)
  1181.   {
  1182.     switch (Lathe->Spline_Type)
  1183.     {
  1184.       /*************************************************************************
  1185.       * Linear spline (nothing more than a simple polygon).
  1186.       **************************************************************************/
  1187.  
  1188.       case LINEAR_SPLINE:
  1189.  
  1190.         /* Use linear interpolation. */
  1191.  
  1192.         A[X] = 0.0;
  1193.         B[X] = 0.0;
  1194.         C[X] = -1.0 * P[i][X] + 1.0 * P[i+1][X];
  1195.         D[X] =  1.0 * P[i][X];
  1196.  
  1197.         A[Y] = 0.0;
  1198.         B[Y] = 0.0;
  1199.         C[Y] = -1.0 * P[i][Y] + 1.0 * P[i+1][Y];
  1200.         D[Y] =  1.0 * P[i][Y];
  1201.  
  1202.         /* Get maximum coordinates in current segment. */
  1203.  
  1204.         x[0] = x[2] = P[i][X];
  1205.         x[1] = x[3] = P[i+1][X];
  1206.  
  1207.         y[0] = y[2] = P[i][Y];
  1208.         y[1] = y[3] = P[i+1][Y];
  1209.  
  1210.         break;
  1211.  
  1212.  
  1213.       /*************************************************************************
  1214.       * Quadratic spline.
  1215.       **************************************************************************/
  1216.  
  1217.       case QUADRATIC_SPLINE:
  1218.  
  1219.         /* Use quadratic interpolation. */
  1220.  
  1221.         A[X] =  0.0;
  1222.         B[X] =  0.5 * P[i][X] - 1.0 * P[i+1][X] + 0.5 * P[i+2][X];
  1223.         C[X] = -0.5 * P[i][X]                   + 0.5 * P[i+2][X];
  1224.         D[X] =                  1.0 * P[i+1][X];
  1225.  
  1226.         A[Y] =  0.0;
  1227.         B[Y] =  0.5 * P[i][Y] - 1.0 * P[i+1][Y] + 0.5 * P[i+2][Y];
  1228.         C[Y] = -0.5 * P[i][Y]                   + 0.5 * P[i+2][Y];
  1229.         D[Y] =                  1.0 * P[i+1][Y];
  1230.  
  1231.         /* Get maximum coordinates in current segment. */
  1232.  
  1233.         x[0] = x[2] = P[i+1][X];
  1234.         x[1] = x[3] = P[i+2][X];
  1235.  
  1236.         y[0] = y[2] = P[i+1][Y];
  1237.         y[1] = y[3] = P[i+2][Y];
  1238.  
  1239.         break;
  1240.  
  1241.  
  1242.       /*************************************************************************
  1243.       * Cubic spline.
  1244.       **************************************************************************/
  1245.  
  1246.       case CUBIC_SPLINE:
  1247.  
  1248.         /* Use cubic interpolation. */
  1249.  
  1250.         A[X] = -0.5 * P[i][X] + 1.5 * P[i+1][X] - 1.5 * P[i+2][X] + 0.5 * P[i+3][X];
  1251.         B[X] =        P[i][X] - 2.5 * P[i+1][X] + 2.0 * P[i+2][X] - 0.5 * P[i+3][X];
  1252.         C[X] = -0.5 * P[i][X]                   + 0.5 * P[i+2][X];
  1253.         D[X] =                        P[i+1][X];
  1254.  
  1255.         A[Y] = -0.5 * P[i][Y] + 1.5 * P[i+1][Y] - 1.5 * P[i+2][Y] + 0.5 * P[i+3][Y];
  1256.         B[Y] =        P[i][Y] - 2.5 * P[i+1][Y] + 2.0 * P[i+2][Y] - 0.5 * P[i+3][Y];
  1257.         C[Y] = -0.5 * P[i][Y]                   + 0.5 * P[i+2][Y];
  1258.         D[Y] =                        P[i+1][Y];
  1259.  
  1260.         /* Get maximum coordinates in current segment. */
  1261.  
  1262.         x[0] = x[2] = P[i+1][X];
  1263.         x[1] = x[3] = P[i+2][X];
  1264.  
  1265.         y[0] = y[2] = P[i+1][Y];
  1266.         y[1] = y[3] = P[i+2][Y];
  1267.  
  1268.         break;
  1269.  
  1270.       default:
  1271.  
  1272.         Error("Unknown lathe type in Compute_Lathe().\n");
  1273.  
  1274.     }
  1275.  
  1276.     Assign_UV_Vect(Lathe->Spline->Entry[i].A, A);
  1277.     Assign_UV_Vect(Lathe->Spline->Entry[i].B, B);
  1278.     Assign_UV_Vect(Lathe->Spline->Entry[i].C, C);
  1279.     Assign_UV_Vect(Lathe->Spline->Entry[i].D, D);
  1280.  
  1281.     /* Get maximum coordinates in current segment. */
  1282.  
  1283.     c[0] = 3.0 * A[X];
  1284.     c[1] = 2.0 * B[X];
  1285.     c[2] = C[X];
  1286.  
  1287.     n = Solve_Polynomial(2, c, r, FALSE, 0.0);
  1288.  
  1289.     while (n--)
  1290.     {
  1291.       if ((r[n] >= 0.0) && (r[n] <= 1.0))
  1292.       {
  1293.         x[n] = r[n] * (r[n] * (r[n] * A[X] + B[X]) + C[X]) + D[X];
  1294.       }
  1295.     }
  1296.  
  1297.     c[0] = 3.0 * A[Y];
  1298.     c[1] = 2.0 * B[Y];
  1299.     c[2] = C[Y];
  1300.  
  1301.     n = Solve_Polynomial(2, c, r, FALSE, 0.0);
  1302.  
  1303.     while (n--)
  1304.     {
  1305.       if ((r[n] >= 0.0) && (r[n] <= 1.0))
  1306.       {
  1307.         y[n] = r[n] * (r[n] * (r[n] * A[Y] + B[Y]) + C[Y]) + D[Y];
  1308.       }
  1309.     }
  1310.  
  1311.     /* Set current segment's bounding cylinder. */
  1312.  
  1313.     tmp_r1[i] = min(min(x[0], x[1]), min(x[2], x[3]));
  1314.     tmp_r2[i] = max(max(x[0], x[1]), max(x[2], x[3]));
  1315.  
  1316.     tmp_h1[i] = min(min(y[0], y[1]), min(y[2], y[3]));
  1317.     tmp_h2[i] = max(max(y[0], y[1]), max(y[2], y[3]));
  1318.  
  1319.     /* Keep track of overall bounding cylinder. */
  1320.  
  1321.     xmin = min(xmin, tmp_r1[i]);
  1322.     xmax = max(xmax, tmp_r2[i]);
  1323.  
  1324.     ymin = min(ymin, tmp_h1[i]);
  1325.     ymax = max(ymax, tmp_h2[i]);
  1326.  
  1327. /*
  1328.     fprintf(stderr, "bound spline segment %d: ", i);
  1329.     fprintf(stderr, "r = %f - %f, h = %f - %f\n", tmp_r1[i], tmp_r2[i], tmp_h1[i], tmp_h2[i]);
  1330. */
  1331.   }
  1332.  
  1333.   /* Set overall bounding cylinder. */
  1334.  
  1335.   Lathe->Radius1 = xmin;
  1336.   Lathe->Radius2 = xmax;
  1337.  
  1338.   Lathe->Height1 = ymin;
  1339.   Lathe->Height2 = ymax;
  1340.  
  1341.   /* Get bounding cylinder. */
  1342.  
  1343.   Lathe->Spline->BCyl = Create_BCyl(Lathe->Number, tmp_r1, tmp_r2, tmp_h1, tmp_h2);
  1344.  
  1345.   /* Get rid of temp. memory. */
  1346.  
  1347.   POV_FREE(tmp_h2);
  1348.   POV_FREE(tmp_h1);
  1349.   POV_FREE(tmp_r2);
  1350.   POV_FREE(tmp_r1);
  1351. }
  1352.  
  1353.  
  1354. /*****************************************************************************
  1355. *
  1356. * FUNCTION
  1357. *
  1358. *   test_hit
  1359. *
  1360. * INPUT
  1361. *
  1362. *   Lathe       - Pointer to lathe structure
  1363. *   Ray         - Current ray
  1364. *   Depth_Stack - Current depth stack
  1365. *   d, w, n     - Intersection depth, parameter and segment number
  1366. *
  1367. * OUTPUT
  1368. *
  1369. *   Depth_Stack
  1370. *
  1371. * RETURNS
  1372. *
  1373. * AUTHOR
  1374. *
  1375. *   Dieter Bayer
  1376. *
  1377. * DESCRIPTION
  1378. *
  1379. *   Test if a hit is valid and push if on the intersection depth.
  1380. *
  1381. * CHANGES
  1382. *
  1383. *   Oct 1996 : Creation.
  1384. *
  1385. ******************************************************************************/
  1386.  
  1387. static int test_hit(Lathe, Ray, Depth_Stack, d, w, n)
  1388. LATHE *Lathe;
  1389. RAY *Ray;
  1390. ISTACK *Depth_Stack;
  1391. DBL d, w;
  1392. int n;
  1393. {
  1394.   VECTOR IPoint;
  1395.  
  1396.   if ((d > DEPTH_TOLERANCE) && (d < Max_Distance))
  1397.   {
  1398.     VEvaluateRay(IPoint, Ray->Initial, d, Ray->Direction);
  1399.  
  1400.     if (Point_In_Clip(IPoint, ((OBJECT *)Lathe)->Clip))
  1401.     {
  1402.       push_entry_i1_d1(d, IPoint, (OBJECT *)Lathe, n, w, Depth_Stack);
  1403.  
  1404.       return(TRUE);
  1405.     }
  1406.   }
  1407.  
  1408.   return(FALSE);
  1409. }
  1410.  
  1411.  
  1412.  
  1413.